import * as THREE from "../../../modules/three/three.module.js";
import { OBB } from '../../../modules/three/jsm/math/OBB.js';
import {MouseButton, WorldConfig} from '../lib/CommonConsts.js';
import EyeIndicator from '../lib/gadget/EyeIndicator.js';
import { OrientationHelper } from '../lib/gadget/OrientationHelper.js';
import {
  bufferAttributeToVectors,
  createContourLine, createContourLineSegments,
  findConvexHull, flatten,
} from '../lib/util/StaticMethods.js';
// import { BoolPolygonsUtil } from '../lib/util/bool-polygons-util.js';
import World3dEvent from './event/World3dEvent.js';
import UndoType from './undo/UndoType.js';
import PlaneRefVO from "../model/PlaneRefVO.js";
import PlaneRefMesh from "../lib/gadget/PlaneRefMesh.js";
import ShapeExtract from "../shaping/ShapeExtract.js";
import ConvexAreaMesh from "../lib/gadget/ConvexAreaMesh.js";
import ShapeExtractAdhere from "../shaping/ShapeExtractAdhere.js";
import ClipperTool from "../lib/clipper_js/ClipperTool.js";

const _vector3 = new THREE.Vector3();

let contourPlane = new THREE.Plane();
let contourLines = []; // array of THREE.Line3
let contourPoints = [];
// 状态 bool 变量
let settingSamplePlane = false;

let cubeVertexes = [];
const planeRefSpheres = [];
const sliceLineSpheres = [];
let sliceLineClosing = false;
let fixedArrowHelpers = [];

const pickedPoints = [];

// 初始化姿态辅助网格
let localFrameMesh;
function initLocalFrameMesh() {
  const cubeHalfSize = 0.5;
  const cubeSize = cubeHalfSize * 2;
  const cubeGeo = new THREE.BoxBufferGeometry(cubeSize, cubeSize, cubeSize);
  const cubeMat = new THREE.MeshLambertMaterial({
    color: '#00006b',
    wireframe: true,
  });
  const cubeMatTransparent = new THREE.MeshBasicMaterial({
    color: '#ffbc11',
    transparent: true,
    opacity: 0.5,
  });
  localFrameMesh = new THREE.Mesh(cubeGeo, cubeMat);
  const cubeMesh = new THREE.Mesh(cubeGeo, cubeMatTransparent);
  localFrameMesh.add(cubeMesh);
}

let slicePlaneMesh;
function initSlicePlaneMesh() {
  const planeSize = 1;
  const planeGeo = new THREE.PlaneBufferGeometry(planeSize, planeSize);
  const mat = new THREE.MeshLambertMaterial({
    color: '#00006b',
    wireframe: true,
  });
  const matTransparent = new THREE.MeshBasicMaterial({
    color: '#ffbc11',
    transparent: true,
    opacity: 0.5,
    side: THREE.DoubleSide,
  });
  slicePlaneMesh = new THREE.Mesh(planeGeo, mat);
  const planeMesh = new THREE.Mesh(planeGeo, matTransparent);
  slicePlaneMesh.add(planeMesh);
}

const triGeo = new THREE.BufferGeometry();
const triPoints = [_vector3, _vector3, _vector3];
triGeo.setAttribute('position', new THREE.BufferAttribute(flatten(triPoints), 3));
triGeo.setIndex([0, 1, 2]);
const triMtl = new THREE.MeshBasicMaterial({color: '#0f3', wireframe: false,
  transparent: true, side: THREE.DoubleSide,
  depthWrite: false, depthTest: false});
const debugTriangleMesh = new THREE.Mesh(triGeo, triMtl);
export function updateDebugTriangle(scene, intersection) {
  if (!intersection || !intersection.object) {
    return;
  }
  scene.add(debugTriangleMesh);
  const {a, b, c} = intersection.face;
  const posAttr0 = intersection.object.geometry.attributes.position;
  const posAttr1 = triGeo.attributes.position;
  posAttr1.copyAt(0, posAttr0, a);
  posAttr1.copyAt(1, posAttr0, b);
  posAttr1.copyAt(2, posAttr0, c);
  posAttr1.applyMatrix4(intersection.object.matrixWorld);
  const triName = [a, b, c].join(',')
  console.log('updateDebugTriangle: ', posAttr1.array.toString(), ', name: ', triName)
  console.log('normal: ', intersection.face.normal.toArray())
  posAttr1.needsUpdate = true;
}

let orientHelper = new OrientationHelper(true);
orientHelper.visible = false;

const sphereGeo0 = new THREE.SphereGeometry(0.1);
const sphereMat0 = new THREE.MeshBasicMaterial({
  color: '#0f0',
  wireframe: true,
});
const slicingSphere = new THREE.Mesh(sphereGeo0, sphereMat0);

const slicingSegment = createContourLineSegments([new THREE.Vector3(0,0,0), new THREE.Vector3(0,0,0)], '#0f0');
slicingSegment.material.depthWrite = false;
slicingSegment.material.depthTest = false;
export function updateSlicingSegment(scene, position, adhering) {
  slicingSphere.position.copy(position);
  slicingSphere.material.color.setStyle(adhering ? '#f00' : '#0f0');
  scene.add(slicingSphere);
  if (sliceLineSpheres.length < 1) {
    return;
  }
  const a = sliceLineSpheres[sliceLineSpheres.length - 1].position;
  if (sliceLineSpheres.length < 2 && !position) {
    return;
  }
  let b = position;
  if (!b) {
    b = sliceLineSpheres[sliceLineSpheres.length - 2].position;
  }
  sliceLineClosing = false;
  sliceLineSpheres[0].scale.set(1, 1, 1)
  if (sliceLineSpheres.length > 2 && position) {
    const firstPos = sliceLineSpheres[0].position;
    const dist = firstPos.distanceToSquared(position);
    if (dist <= WorldConfig.slicingAdhereRadiusSq) {
      sliceLineClosing = true;
      position.copy(firstPos);
      sliceLineSpheres[0].scale.set(4, 4, 4);
    }
  }
  if (!slicingSegment.parent) {
    scene.add(slicingSegment);
  }
  const posAttr = slicingSegment.geometry.attributes.position;
  posAttr.setXYZ(0, a.x, a.y, a.z);
  posAttr.setXYZ(1, b.x, b.y, b.z);
  posAttr.needsUpdate = true;
}

// 方向控制器
export default class EditOrientation {
  _frontFacing = new THREE.Vector3(0, 1, 0);
  world3d;
  /**
   * @type {PlaneRefMesh|null}
   */
  addingPlaneRef;
  /**
   * @type {ShapeExtract}
   */
  shapeExtract;
  /**
   * @type {ShapeExtractAdhere}
   */
  shapeExtractAdhere;
  cuttingSegments = [];

  constructor(world3d) {
    this.world3d = world3d;
    this.world3d.scene.add(orientHelper);
    orientHelper.visible = false;
    initLocalFrameMesh();
    initSlicePlaneMesh();
    this.shapeExtract = new ShapeExtract(world3d);
    this.shapeExtractAdhere = new ShapeExtractAdhere(world3d);
  }

  // 当凸包轮廓出现后，点击鼠标来新增固定视角
  _addOrientationArrow() {
    console.log('add orient: ', orientHelper.orient);
    const plane = new THREE.Plane().setFromNormalAndCoplanarPoint(orientHelper.orient, orientHelper.position);
    console.log('plane: ', plane);
    const arrowHelperFixed = orientHelper.convertToArrowHeler();
    this.world3d.scene.add(arrowHelperFixed);
    fixedArrowHelpers.push(arrowHelperFixed);
    const eyeIndicator = new EyeIndicator();
    const indicatorPos = arrowHelperFixed.position
      .clone()
      .add(
        arrowHelperFixed.orient
          .clone()
          .multiplyScalar(WorldConfig.eye_to_face_distance),
      );
    eyeIndicator.position.copy(indicatorPos);
    // eyeIndicator.quaternion.copy(arrowHelperFixed.quaternion)
    eyeIndicator.up.copy(this.world3d.camera.up);
    eyeIndicator.setFocus(arrowHelperFixed.position);
    this.world3d.scene.add(eyeIndicator);
    this.world3d.store.fixedEyeIndicators.push(eyeIndicator);
    this.world3d.scene.dispatchEvent(World3dEvent.eyeIndicatorsChanged);
  }

  // 当凸包轮廓出现后，移动鼠标时，根据 当前鼠标位置 到 轮廓的最短距离 来设置方位指示器 orientHelper 的朝向
  _updateOrientationArrow() {
    const intersectPoint = this.world3d.mouseRaycaster.ray.intersectPlane(
      contourPlane,
      new THREE.Vector3(),
    );
    if (!intersectPoint) {
      return;
    }
    let closestPoint;
    let minDistance = Infinity;
    let minIndex = 0;
    contourLines.forEach((line3, index) => {
      const t = line3.closestPointToPointParameter(intersectPoint, false);
      if (t < 0 || t > 1) {
        return;
      }
      const pointOnContour = line3
        .delta(new THREE.Vector3())
        .multiplyScalar(t)
        .add(line3.start);
      const dist = pointOnContour.distanceToSquared(intersectPoint);
      if (minDistance > dist) {
        minDistance = dist;
        minIndex = index;
        closestPoint = pointOnContour;
      }
    });
    if (closestPoint) {
      orientHelper.position.copy(closestPoint);
      _vector3.copy(intersectPoint).sub(closestPoint);
      _vector3.normalize();
      if (
        contourPoints.length &&
        // BoolPolygonsUtil.isInConvex(intersectPoint, contourPoints)
        ClipperTool.pointInContour(intersectPoint, contourPoints)
      ) {
        _vector3.negate();
      }
      orientHelper.setDirection(_vector3);
      orientHelper.visible = true;
    }
  }

  // 结束固定视角的添加
  stopAddOrientations() {
    orientHelper.visible = false;
    const contourLineSegment = this.world3d.scene.children.find(
      (it) => it.name === 'convex contour',
    );
    if (contourLineSegment) {
      contourLineSegment.removeFromParent();
    }
    fixedArrowHelpers.forEach((it) => it.removeFromParent());
    fixedArrowHelpers.length = 0;
  }

  // 开始添加固定视角
  startSettingOrientation() {
    fixedArrowHelpers.forEach((it) => it.removeFromParent());
    fixedArrowHelpers.length = 0;
  }

  // 开始设置矩形采样空间
  startSettingRect() {
    localFrameMesh.rotation.set(0, 0, 0);
    // settingSamplePlane = false
    slicePlaneMesh.removeFromParent();
    pickedPoints.length = 0;
  }

  startAddingPlaneRef() {
    localFrameMesh.removeFromParent();
    slicePlaneMesh.removeFromParent();
    pickedPoints.length = 0;
    orientHelper.visible = false;
  }

  // 开始设置轮廓采样空间
  startSettingPlane() {
    slicePlaneMesh.rotation.set(0, 0, 0);
    // settingSamplePlane = true
    localFrameMesh.removeFromParent();
  }

  beFree() {
    this.world3d.transformRotateControl.detach();
    localFrameMesh.removeFromParent();
    cubeVertexes.forEach((it) => it.removeFromParent());
    cubeVertexes.length = 0;

    slicePlaneMesh.removeFromParent();

    this.stopAddOrientations();
  }

  startSetQuaternion() {
    localFrameMesh.rotation.set(0, 0, 0);
    localFrameMesh.position.copy(this.world3d.cameraControls.target);
    this.world3d.scene.add(localFrameMesh);
    this.world3d.transformRotateControl.attach(localFrameMesh);
  }

  // 通过输入的数字来直接改变 offsetParent 的姿态
  setQuaternionDirectly() {
    if (!localFrameMesh.parent) {
      return;
    }
    const offsetParent = this.world3d.offsetParent;
    // offsetParent.quaternion.copy(localFrameMesh.getWorldQuaternion(new THREE.Quaternion()).invert())
    offsetParent.quaternion.premultiply(
      localFrameMesh.getWorldQuaternion(new THREE.Quaternion()).invert(),
    );
    this.world3d.transformRotateControl.detach();
    localFrameMesh.removeFromParent();
  }

  // 添加一个属于矩形采样空间的顶点
  _addCubeVertexHelper(intersectPoint) {
    const sphereGeo = new THREE.SphereGeometry(0.04);
    const sphereMat = new THREE.MeshBasicMaterial({
      color: '#0b0',
      wireframe: true,
    });
    const sphere = new THREE.Mesh(sphereGeo, sphereMat);
    this.world3d.scene.add(sphere);
    cubeVertexes.push(sphere);
    sphere.position.copy(intersectPoint);
    console.log('picking: ', intersectPoint.toArray());
    pickedPoints.push(intersectPoint);
    if (cubeVertexes.length >= 5) {
      console.log('picked: ', pickedPoints.map(it => it.toArray()));
      // 已经添加了五个矩形采样空间的顶点，可以绘制出一个长方体 代表采样空间
      const points = cubeVertexes.map(it => it.position);
      const box3 = new THREE.Box3().setFromPoints(points);
      box3.expandByVector(new THREE.Vector3(0.3, 0.3, 0));
      const size = box3.getSize(new THREE.Vector3());
      const center = box3.getCenter(new THREE.Vector3());
      localFrameMesh.scale.set(size.x, size.y, size.z);
      localFrameMesh.position.copy(center);
      this.world3d.scene.add(localFrameMesh);
      // 把3d 位移 旋转 缩放工具挂到 长方体上
      this.world3d.transformRotateControl.attach(localFrameMesh);
      this.world3d.store.freeState();
      cubeVertexes.forEach((it) => it.removeFromParent());
      cubeVertexes.length = 0;
    }
  }

  _addSliceLineVertex(intersectPoint) {
    if (!sliceLineClosing) {
      const sphereGeo = new THREE.SphereGeometry(0.05);
      const sphereMat = new THREE.MeshBasicMaterial({
        color: '#2263dd',
        wireframe: true,
      });
      const sphere = new THREE.Mesh(sphereGeo, sphereMat);
      this.world3d.scene.add(sphere);
      sliceLineSpheres.push(sphere);
      sphere.position.copy(intersectPoint);
    }
    if (sliceLineSpheres.length > 1) {
      if (!slicingSegment.parent) {
        this.world3d.scene.add(slicingSegment);
      }
      // updateSlicingSegment(this.world3d.scene);
      const adhereArr = this.shapeExtractAdhere.pointerDown4Cut();
      let linePoints;
      let a = sliceLineSpheres[sliceLineSpheres.length - 1].position;
      let b = sliceLineSpheres[sliceLineSpheres.length - 2].position;
      if (sliceLineClosing) {
        b = a;
        a = sliceLineSpheres[0].position;
      }

      if (adhereArr.length) { // 切割线段复用
        if (this.shapeExtractAdhere.firstPointAdhering && sliceLineSpheres.length > 2) {
          // 这里的 sliceLineClosing 通常为 false
          sliceLineClosing = true;
          if (adhereArr.length < 2) {
            linePoints = this.shapeExtract.computeCutLines(b, a);
          }
        }
        adhereArr.forEach(adhere => {
          const {lineStart, lineEnd, position, rotation} = adhere;
          const pts = this.shapeExtract.computeIntersectSegments(lineStart, lineEnd, position, rotation);
          if (!linePoints) {
            linePoints = pts;
          }
        });
      } else {
        linePoints = this.shapeExtract.computeCutLines(b, a);
      }
      if (linePoints.length > 1 && !adhereArr.length) {
        const segmentSlice = createContourLineSegments(linePoints, ConvexAreaMesh.defaultColor);
        segmentSlice.material.depthWrite = true;
        segmentSlice.material.depthTest = true;
        this.world3d.scene.add(segmentSlice);
        this.cuttingSegments.push(segmentSlice);
        const ctx = {
          scene: segmentSlice.parent,
          segmentSlice,
          shapeExtract: this.shapeExtract,
          lineStart: b,
          lineEnd: a,
          cameraPosition: this.world3d.camera.position.clone(),
          cameraRotation: this.world3d.camera.rotation.clone(),
          sphere: sliceLineSpheres[sliceLineSpheres.length - 1],
          sphereArr: sliceLineSpheres,
          store: this.world3d.store,
          segments: this.cuttingSegments,
        };
        this.world3d.editRecord.addAction(UndoType.addSliceSegment, ctx);
      }
    } else if (sliceLineSpheres.length === 1) {
      this.shapeExtractAdhere.setFirstAdherePoint();
    }
  }

  // 添加一个属于辅助平面的参考点
  _addPlaneRefVertex(intersectPoint) {
    const sphereGeo = new THREE.SphereGeometry(0.04);
    const sphereMat = new THREE.MeshBasicMaterial({
      color: '#0bb',
      wireframe: true,
    });
    const sphere = new THREE.Mesh(sphereGeo, sphereMat);
    this.world3d.scene.add(sphere);
    planeRefSpheres.push(sphere);
    sphere.position.copy(intersectPoint);
    if (planeRefSpheres.length >= 4) {
      if (!this.addingPlaneRef) {
        const vo = new PlaneRefVO();
        const refMesh = new PlaneRefMesh();
        refMesh.initPlaneRef(vo);
        this.addingPlaneRef = refMesh;
        this.world3d.scene.add(refMesh);
      }
      const points = planeRefSpheres.map(it => it.position);
      this.addingPlaneRef.updateBySamplePoints(points, this.world3d.camera.position);

      const ctx = {
        scene: sphere.parent,
        planeRefSpheres: planeRefSpheres,
        sphereMesh: sphere,
        planeRefMesh: this.addingPlaneRef,
        eyePos: this.world3d.camera.position.clone(),
      };
      this.world3d.editRecord.addAction(UndoType.addPlaneRefPoint, ctx);
    }
  }

  // 添加一个属于切割平面的顶点
  _addPlaneVertexHelper(intersectPoint) {
    const sphereGeo = new THREE.SphereGeometry(0.04);
    const sphereMat = new THREE.MeshBasicMaterial({
      color: '#8b2da8',
      wireframe: true,
    });
    const sphere = new THREE.Mesh(sphereGeo, sphereMat);
    this.world3d.scene.add(sphere);
    cubeVertexes.push(sphere);
    sphere.position.copy(intersectPoint);
    if (cubeVertexes.length >= 4) {
      const a = cubeVertexes[0].position;
      const b = cubeVertexes[1].position;
      const c = cubeVertexes[2].position;
      const d = cubeVertexes[3].position;
      const box3 = new THREE.Box3().setFromPoints([a, b, c, d]);
      box3.expandByVector(new THREE.Vector3(0.3, 0.3, 0));
      const size = box3.getSize(new THREE.Vector3());
      const center = box3.getCenter(new THREE.Vector3());
      center.z = d.z;
      slicePlaneMesh.scale.set(size.x, size.y, 1);
      slicePlaneMesh.position.copy(center);
      this.world3d.scene.add(slicePlaneMesh);
      this.world3d.transformRotateControl.attach(slicePlaneMesh);
      settingSamplePlane = false;
      cubeVertexes.forEach((it) => it.removeFromParent());
      cubeVertexes.length = 0;
    }
  }

  /**
   * 长方体采样空间设置完成后，根据空间内的顶点 寻找一个凸包轮廓
   * @return {boolean} true 表示凸包轮廓创建成功
   */
  sampleOutRect() {
    const existedContour = this.world3d.scene.children.find(
      (it) => it.name === 'convex contour',
    );
    if (existedContour) {
      existedContour.removeFromParent();
    }
    if (!localFrameMesh.parent) {
      return false;
    }
    localFrameMesh.geometry.computeBoundingBox();
    const sampleObb = new OBB().fromBox3(localFrameMesh.geometry.boundingBox);
    sampleObb.applyMatrix4(localFrameMesh.matrixWorld);
    let sampleBox3 = localFrameMesh.geometry.boundingBox.clone();
    sampleBox3.applyMatrix4(localFrameMesh.matrixWorld);
    const involvedTileMeshes = []; // 保存若干个与采样空间有交集的 b3dms 瓦片网格
    this.world3d.tiles.group.traverse((obj3d) => {
      if (obj3d instanceof THREE.Mesh && obj3d.visible) {
        const tileBox3 = obj3d.geometry.boundingBox.clone();
        tileBox3.applyMatrix4(obj3d.matrixWorld);
        if (sampleBox3.intersectsBox(tileBox3)) {
          involvedTileMeshes.push(obj3d);
        }
      }
    });
    // console.log('involvedTileMeshes: ', involvedTileMeshes)
    const involvedVectors = [];
    involvedTileMeshes.forEach((mesh) => {
      const vectors = bufferAttributeToVectors(
        mesh.geometry.attributes.position,
      );
      vectors.forEach((vector) => {
        vector.applyMatrix4(mesh.matrixWorld);
        if (sampleObb.containsPoint(vector)) {
          involvedVectors.push(vector);
        }
      });
    });
    if (involvedVectors.length < 2) {
      console.error(
        '长方体采样空间没有包含足够的顶点，无法采样出轮廓，',
        involvedVectors.length,
      );
      this.removeSampleCube();
      return false;
    }
    const convexHull = findConvexHull(involvedVectors);
    console.log('convexHull: ', convexHull);
    const contourLineSegment = createContourLine(
      convexHull,
      localFrameMesh.position.z,
    );
    contourLineSegment.name = 'convex contour';
    this.world3d.scene.add(contourLineSegment);
    this.removeSampleCube();
    contourPlane.set(new THREE.Vector3(0, 0, 1), -localFrameMesh.position.z);
    const contourVectors = bufferAttributeToVectors(
      contourLineSegment.geometry.attributes.position,
    );
    contourLines.length = 0;
    contourPoints.length = 0;
    for (let i = 0; i < contourVectors.length - 1; i++) {
      const a = contourVectors[i];
      const b = contourVectors[i + 1];
      const line3 = new THREE.Line3(a, b);
      contourLines.push(line3);
      contourPoints.push(a);
    }
    return true;
  }

  // 删除采样长方体
  removeSampleCube() {
    if (this.world3d.transformRotateControl.object === localFrameMesh) {
      this.world3d.transformRotateControl.detach();
      const ctx = {
        cube: localFrameMesh,
        scene: this.world3d.scene,
        transformControl: this.world3d.transformRotateControl,
      };
      this.world3d.editRecord.addAction(UndoType.removeSampleCube, ctx);
    }
    this.world3d.scaleControl.detach();
    localFrameMesh.removeFromParent();
  }

  // 通过 UI交互 来使用固定视角
  useEyeIndicatorByObj(dataObj) {
    const store = this.world3d.store;
    const eyeIndicator = store.fixedEyeIndicators.find(
      (it) => it.dataObj.id === dataObj.id,
    );
    if (eyeIndicator) {
      store.setUsingFixedEye(eyeIndicator);
      this.useEyeIndicator();
    }
  }

  // 使用固定视角来设置当前相机的位置 朝向 焦点
  useEyeIndicator() {
    const eyeIndicator = this.world3d.store.getUsingFixedEye();
    if (!eyeIndicator) {
      return false;
    }
    this.world3d._selectFixedEyePlugin.detachItem();
    this.world3d.onCameraTargetChange(
      eyeIndicator.eyeFacing,
      eyeIndicator.focus,
      eyeIndicator.getDist(),
    );
    // const camera = this.world3d.camera
    // camera.position.copy(previousEyeIndicator.position)
    // cameraControl.update()

    const event = World3dEvent.eyeIndicatorSelected;
    event.value.pos.copy(eyeIndicator.position);
    event.value.target.copy(eyeIndicator.focus);
    event.value.distance = eyeIndicator.getDist();
    event.value.id = eyeIndicator.dataObj.id;
    this.world3d.scene.dispatchEvent(event);
    return true;
  }

  goTopByFixedEye() {
    const eyeIndicator = this.world3d.store.getUsingFixedEye();
    if (!eyeIndicator) {
      return false;
    }
    const focus = this.world3d.cameraControls.target; // eyeIndicator.focus
    const distance = WorldConfig.eye_to_face_distance * 2;
    const orient = new THREE.Vector3(0, 0, -1);
    this.world3d.onCameraTargetChange(orient, focus, distance);
    const plane = new THREE.Plane(new THREE.Vector3(0, 0, 1), 0);
    const p = plane.projectPoint(eyeIndicator.eyeFacing, new THREE.Vector3());
    this._frontFacing.copy(p).normalize();
    // this._frontFacing.copy(eyeIndicator.eyeFacing)
  }

  // 更新视角指示器的显隐
  updateEyeIndicatorsVisible() {
    if (this.world3d.store.fixedEyesIsHidden()) {
      return;
    }
    const facing = this.world3d.cameraControls.target
      .clone()
      .sub(this.world3d.camera.position)
      .normalize();
    this.world3d.store.fixedEyeIndicators.forEach((it) => {
      const dot = it.eyeFacing.dot(facing);
      it.visible = dot < 0.98;
    });
  }

  removeEyeIndicator() {
    const store = this.world3d.store;
    const eyeIndicator = store.pickingEyeIndicator();
    if (!eyeIndicator) {
      return;
    }
    this._removeEyeWithRecord(eyeIndicator);
    const index = store.fixedEyeIndicators.indexOf(eyeIndicator);
    store.fixedEyeIndicators.splice(index, 1);
    eyeIndicator.removeFromParent();
    this.world3d.scene.dispatchEvent(World3dEvent.eyeIndicatorsChanged);
    this.world3d.scene.dispatchEvent(World3dEvent.clearPaneSelection);
  }

  // 通过 UI交互 来删除固定视角
  removeEyeIndicatorByObj(eyeObj) {
    const store = this.world3d.store;
    const index = store.fixedEyeIndicators.findIndex(
      (it) => it.dataObj.id === eyeObj.id,
    );
    if (index >= 0) {
      const eyeIndicator = store.fixedEyeIndicators[index];
      const pickingEye = store.pickingEyeIndicator();
      if (pickingEye && pickingEye === eyeIndicator) {
        this.world3d.scene.dispatchEvent(World3dEvent.clearPaneSelection);
      }
      this._removeEyeWithRecord(eyeIndicator);
      eyeIndicator.removeFromParent();
      store.fixedEyeIndicators.splice(index, 1);
      this.world3d.scene.dispatchEvent(World3dEvent.eyeIndicatorsChanged);
    }
  }

  _removeEyeWithRecord(eyeIndicator) {
    const store = this.world3d.store;
    const ctx = {
      indicator: eyeIndicator,
      scene: this.world3d.scene,
      arr: store.fixedEyeIndicators,
    };
    this.world3d.editRecord.addAction(UndoType.removeEye, ctx);
  }

  // 添加固定视角 并保存到操作栈，可撤销
  addEyeIndicatorWithRecord() {
    const eyeIndicator = this.addEyeIndicator();
    const store = this.world3d.store;
    const ctx = {
      indicator: eyeIndicator,
      scene: this.world3d.scene,
      arr: store.fixedEyeIndicators,
    };
    this.world3d.editRecord.addAction(UndoType.addEye, ctx);
  }

  addEyeIndicator(eyePos, eyeTarget) {
    const pos = eyePos ? eyePos : this.world3d.camera.position;
    const target = eyeTarget ? eyeTarget : this.world3d.cameraControls.target;
    const eyeIndicator = new EyeIndicator();
    eyeIndicator.position.copy(pos);
    // eyeIndicator.quaternion.copy(arrowHelperFixed.quaternion)
    eyeIndicator.up.copy(this.world3d.camera.up);
    eyeIndicator.setFocus(target);
    this.world3d.scene.add(eyeIndicator);
    this.world3d.store.fixedEyeIndicators.push(eyeIndicator);
    this.world3d.scene.dispatchEvent(World3dEvent.eyeIndicatorsChanged);
    return eyeIndicator;
  }

  // 根据当前相机的位置 焦点 朝向 来更新选中的固定视角
  updateEyeIndicator() {
    const eyeIndicator = this.world3d.store.getUsingFixedEye();
    if (!eyeIndicator) {
      return;
    }
    const ctx = {
      indicator: eyeIndicator,
      pos: eyeIndicator.position.clone(),
      focus: eyeIndicator.focus.clone(),
    };
    this.world3d.editRecord.addAction(UndoType.updateEye, ctx);
    eyeIndicator.position.copy(this.world3d.camera.position);
    eyeIndicator.setFocus(this.world3d.cameraControls.target);
    ctx.posNew = eyeIndicator.position.clone();
    ctx.focusNew = eyeIndicator.focus.clone();
    this.world3d.scene.dispatchEvent(World3dEvent.eyeIndicatorsChanged);
  }

  getEyeDataObjs() {
    return this.world3d.store.fixedEyeIndicators.map((it) => it.getDataObj());
  }

  endAddPlaneRef() {
    const store = this.world3d.store;
    store.freeState();
    if (this.addingPlaneRef) {
      store.planeRefMeshes.push(this.addingPlaneRef);
      this.addingPlaneRef = null;
    }
    planeRefSpheres.forEach(it => it.removeFromParent());
    planeRefSpheres.length = 0;
  }

  endAddSliceLine() {
    const store = this.world3d.store;
    store.freeState();
    this._onConvexAreaMeshAdd();
    this.world3d.toggleTileLock(false);
  }

  _onConvexAreaMeshAdd() {
    sliceLineSpheres.forEach(it => it.removeFromParent());
    sliceLineSpheres.length = 0;
    slicingSegment.removeFromParent();
    slicingSphere.removeFromParent();
    sliceLineClosing = false;
    this.cuttingSegments.forEach(it => {
      if (it.parent instanceof THREE.Scene) {
        it.removeFromParent();
      }
    });
    this.cuttingSegments.length = 0;
  }

  // 鼠标按下的回调
  pointerDown(event) {}

  pointerMove(event) {
    const store = this.world3d.store;
    if (store.stateAddingFixedEye) {
      this._updateOrientationArrow();
    } else if (store.stateAddingSliceLine) {
      const results = this.world3d.mouseRaycaster.intersectObject(this.world3d.tiles.group, true);
      if (!results.length) {
        return;
      }
      const intersect = results[0];
      let adherePos = this.shapeExtractAdhere.pointerMove4Cut(intersect.point);
      const pos = adherePos || intersect.point;
      updateSlicingSegment(this.world3d.scene, pos, !!adherePos);
    }
  }

  pointerUpUnmoved(event) {
    const store = this.world3d.store;
    if (event.button === MouseButton.right) {
      // mouse right button down
      if (store.stateAddingFixedEye) {
        this.world3d.endAddOrientaion();
      } else if (store.stateAddingPlaneRef) {
        this.endAddPlaneRef();
      } else if (store.stateAddingSliceLine) {
        this.endAddSliceLine();
      }
      this.shapeExtract.clearRagMesh();
      return;
    }
    this.shapeExtract.pointerUpUnmoved(event);
    if (store.stateAddingSampleCubeVert || settingSamplePlane) {
      const results = this.world3d.mouseRaycaster.intersectObject(
        this.world3d.tiles.group,
        true,
      );
      if (!results.length) {
        return;
      }
      const intersect = results[0];
      if (store.stateAddingSampleCubeVert) {
        this._addCubeVertexHelper(intersect.point);
      } else {
        this._addPlaneVertexHelper(intersect.point);
      }
      // updateDebugTriangle(this.world3d.scene, results[0]);
    } else if (store.stateAddingFixedEye) {
      this._addOrientationArrow();
    } else if (store.stateAddingPlaneRef || store.stateAddingSliceLine) {
      const results = this.world3d.mouseRaycaster.intersectObject(
        this.world3d.tiles.group,
        true,
      );
      if (!results.length) {
        return;
      }
      const intersect = results[0];
      if (store.stateAddingPlaneRef) {
        this._addPlaneRefVertex(intersect.point);
      } else {
        const pos = this.shapeExtractAdhere.adheringPoint || intersect.point;
        this._addSliceLineVertex(pos);
        if (sliceLineClosing) {
          const geoArea = this.shapeExtract.computeClosedAreaGeometry();
          if (geoArea) {
            const convexMesh = new ConvexAreaMesh(geoArea);
            convexMesh.createVO(this.shapeExtract);
            convexMesh.initContour(this.cuttingSegments);
            this.cuttingSegments.length = 0;
            convexMesh.renderOrder = WorldConfig.order_surfaces_area;
            this.world3d.scene.add(convexMesh);
            store.surfacesAreaMeshes.push(convexMesh);
          }
          this._onConvexAreaMeshAdd();
          this.shapeExtract.clearCutCache();
          this.shapeExtract.clearUndo();
          this.shapeExtractAdhere.onAreaAdded();
        }
      }
    }
  }

  pointerUpMoved(event) {}
}
